/*
 * $RCSfile: MainFrame.java,v $
 * $Revision: 1.1 $
 * $Date: 2009-10-12 $
 *
 * Copyright (C) 2005 Skin, Inc. All rights reserved.
 *
 * This software is the proprietary information of Skin, Inc.
 * Use is subject to license terms.
 */
package com.skin.generate.gui;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.io.File;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JToolBar;
import javax.swing.JTree;
import javax.swing.ScrollPaneConstants;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.tree.DefaultTreeModel;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.skin.generate.gui.container.BaseFrame;
import com.skin.generate.gui.container.BasePanel;
import com.skin.generate.gui.event.ClickListener;
import com.skin.generate.gui.event.TreeClickListener;
import com.skin.generate.gui.tree.DatabaseTreeCellRenderer;
import com.skin.generate.gui.tree.DatabaseTreeNode;
import com.skin.generate.gui.tree.UserObject;
import com.skin.generate.gui.util.SqlFile;
import com.skin.generate.gui.util.TableUtil;
import com.skin.webcat.database.Table;
import com.skin.webcat.datasource.ConnectionConfig;
import com.skin.webcat.datasource.ConnectionManager;
import com.skin.webcat.util.Webcat;

/**
 * <p>Title: MainFrame</p>
 * <p>Description: </p>
 * <p>Copyright: Copyright (c) 2006</p>
 * @author xuesong.net
 * @version 1.0
 */
public class MainFrame extends BaseFrame {
    static final long serialVersionUID = 1L;
    static final Logger logger = LoggerFactory.getLogger(MainFrame.class);

    JPanel contentPanel;
    JTree jTree;
    DatabaseTreeNode rootNode;
    JScrollPane jScrollPane;
    JSplitPane jSplitPane;

    JButton codeButton;
    JButton saveButton;
    JButton loadButton;
    LoadingDialog loadingDialog;
    LocalStorage localStorage;

    /**
     * storage
     */
    private static final String LOCAL_STORAGE_FILE = "classes/storage.ini";

    /**
     * default
     */
    public MainFrame() {
        super();
    }

    /**
     * show
     */
    public void open() {
        this.initialize();
        this.setVisible(true);

        this.loading(new Runnable() {
            @Override
            public void run() {
                showConnectionList();
            }
        });
    }

    /**
     * Initialize the class.
     */
    void initialize() {
        this.setName("JFrame1");
        this.setTitle(Constant.APP_NAME);
        this.setIconImage(SwingManager.getImage("resource/icon.gif"));
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);

        int defaultFontSize = SwingManager.getDefaultFontSize();
        SwingManager.setScale(defaultFontSize / 12.0f);

        this.setContentPane(getContentPanel());

        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        Dimension frameSize = this.getSize();

        if(frameSize.height > screenSize.height) {
            frameSize.height = screenSize.height;
        }

        if(frameSize.width > screenSize.width)  {
            frameSize.width = screenSize.width;
        }

        int width = SwingManager.getScaleSize(960);
        int height = SwingManager.getScaleSize(600);
        this.setSize(width, height);
        SwingManager.setCenter(this);
        this.localStorage = LocalStorage.getStorage(new File(LOCAL_STORAGE_FILE), "utf-8");
        this.registe("/webcat/table/list", "com.skin.generate.gui.table.TableListPanel");
        this.registe("/webcat/table/edit", "com.skin.generate.gui.table.TableEditPanel");
        this.registe("/webcat/sql/list", "com.skin.generate.gui.table.TableListPanel");
        this.registe("/webcat/sql/edit", "com.skin.generate.gui.table.TableEditPanel");
    }

    /**
     * @return JPanel
     */
    JPanel getContentPanel() {
        if(this.contentPanel == null) {
            this.contentPanel = new JPanel();
            this.contentPanel.setLayout(new java.awt.BorderLayout());
            this.contentPanel.add(getJToolBar(), java.awt.BorderLayout.NORTH);
            this.contentPanel.add(getJSplitPane(), java.awt.BorderLayout.CENTER);
            this.contentPanel.add(getCopyrightPane(), java.awt.BorderLayout.SOUTH);
        }
        return this.contentPanel;
    }

    /**
     * @return JToolBar
     */
    JToolBar getJToolBar() {
        JToolBar jToolBar = new JToolBar();
        jToolBar.setFloatable(false);
        jToolBar.setBorder(new EmptyBorder(4, 4, 4, 4));
        jToolBar.add(this.getLoadMenu());
        jToolBar.add(this.getPreferencesMenu());
        jToolBar.add(this.getHelpMenu());
        return jToolBar;
    }

    /**
     * @return JSplitPane
     */
    JSplitPane getJSplitPane() {
        if(this.jSplitPane == null) {
            this.jSplitPane = new JSplitPane();
            this.jSplitPane.setLeftComponent(this.getJTreePanel());
            this.jSplitPane.setRightComponent(this.getBlankPanel());
            this.jSplitPane.setDividerLocation(SwingManager.getScaleSize(240));
        }
        return this.jSplitPane;
    }

    /**
     * @return JScrollPane
     */
    JScrollPane getJTreePanel() {
        if(this.jScrollPane == null) {
            this.jScrollPane = new JScrollPane();
            this.jScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
            this.jScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
            this.jScrollPane.setViewportView(getJTree());
        }
        return this.jScrollPane;
    }

    JTree getJTree() {
        if(this.rootNode == null) {
            this.rootNode = new DatabaseTreeNode(new UserObject("webcat", "root"), SwingManager.getImageIcon("resource/root.gif"));
        }

        if(this.jTree == null) {
            DatabaseTreeCellRenderer renderer = new DatabaseTreeCellRenderer();
            renderer.setFont(SwingManager.getDefaultFont());
            renderer.setLeafIcon(SwingManager.getImageIcon("resource/table.gif")); 
            renderer.setClosedIcon(SwingManager.getImageIcon("resource/folder.gif")); 
            renderer.setOpenIcon(SwingManager.getImageIcon("resource/folderopen.gif"));

            DefaultTreeModel model = new DefaultTreeModel(this.rootNode);
            EmptyBorder emptyBorder = new EmptyBorder(5, 5, 5, 5);

            this.jTree = new JTree(model);
            this.jTree.setCellRenderer(renderer);
            this.jTree.setBorder(emptyBorder);
            this.jTree.setRowHeight(SwingManager.getScaleSize(15));
            this.jTree.addTreeSelectionListener(new TreeClickListener() {
                @Override
                public void click(final TreeSelectionEvent e) {
                    loading(new Runnable() {
                        @Override
                        public void run() {
                            onTreeNodeClick(e);
                        }
                    });
                }
            });
        }
        return this.jTree;
    }

    JPanel getCopyrightPane() {
        JPanel jpanel = new JPanel();
        jpanel.setBorder(new LineBorder(new Color(120, 120, 120), 1, true));
        jpanel.add(new JLabel("Copyright (C) 2008-2017 Skin, Inc. All rights reserved."));
        return jpanel;
    }

    void onTreeNodeClick(TreeSelectionEvent event) {
        DatabaseTreeNode node = getSelectedTreeNode();

        if(node == null || node.isRoot()) {
            return;
        }

        UserObject userObject = (UserObject)(node.getUserObject());
        logger.debug("userObject: {}", userObject);

        if(userObject == null) {
            return;
        }

        try {
            String action = userObject.getAction();
            String showChildNodesMethod = userObject.getString("showChildNodesMethod");
            logger.info("action: {}, method: {}", action, showChildNodesMethod);
    
            if(showChildNodesMethod != null) {
                this.showChildNodes(node, showChildNodesMethod);
            }

            if(action != null) {
                this.dispatch(action, userObject.getParameters());
            }
        }
        catch(Exception e) {
            logger.error(e.getMessage(), e);
            error(e);
        }
    }

    /**
     * @param panel
     * @param params
     */
    @Override
    public void display(BasePanel panel, Map<String, Object> params) {
        this.jSplitPane.setRightComponent(panel);
    }

    JButton getLoadMenu() {
        if(this.loadButton == null) {
            this.loadButton = new JButton(" 装 载 ");
            this.loadButton.setFont(SwingManager.getDefaultFont());
            this.loadButton.setMargin(new Insets(0, 4, 0, 4));
            this.loadButton.setBorder(new EmptyBorder(5, 5, 5, 5));

            this.loadButton.addActionListener(new ClickListener(){
                @Override
                public void click(ActionEvent actionEvent) {
                    loadTable();
                }
            });
        }
        return this.loadButton;
    }

    /**
     * @return DefaultMutableTreeNode
     */
    DatabaseTreeNode getSelectedTreeNode() {
        return (DatabaseTreeNode)(this.jTree.getLastSelectedPathComponent());
    }

    JButton getPreferencesMenu() {
        JButton mb2 = new JButton(" 首选项 ");
        mb2.setFont(SwingManager.getDefaultFont());
        mb2.setMargin(new Insets(0, 4, 0, 4));
        mb2.setBorder(new EmptyBorder(5, 5, 5, 5));
        mb2.setEnabled(false);

        mb2.addActionListener(new ClickListener(){
            @Override
            public void click(ActionEvent actionEvent) {
                message("尚未实现的功能！");
            }
        });
        return mb2;
    }

    JButton getHelpMenu() {
        JButton mb2 = new JButton(" 帮助 ");
        mb2.setFont(SwingManager.getDefaultFont());
        mb2.setMargin(new Insets(0, 4, 0, 4));
        mb2.setBorder(new EmptyBorder(5, 5, 5, 5));
        mb2.setEnabled(false);

        mb2.addActionListener(new ClickListener(){
            @Override
            public void click(ActionEvent actionEvent) {
                message("尚未实现的功能！");
            }
        });
        return mb2;
    }

    void showConnectionList() {
        try {
            Collection<ConnectionConfig> connectionList = ConnectionManager.getConnectionList();

            if(connectionList == null || connectionList.isEmpty()) {
                logger.debug("no connection.");
            }
            else {
                this.rootNode.removeAllChildren();
                Iterator<ConnectionConfig> iterator = connectionList.iterator();

                while(iterator.hasNext()) {
                    ConnectionConfig connectionConfig = iterator.next();

                    UserObject userObject = new UserObject(connectionConfig.getName(), "/webcat/table/list");
                    userObject.setParameter("name", connectionConfig.getName());
                    userObject.setParameter("showChildNodesMethod", "showTableList");
                    DatabaseTreeNode treeNode = new DatabaseTreeNode(userObject, SwingManager.getImageIcon("resource/dbclose.gif"));
                    this.rootNode.add(treeNode);
                }
            }

            /**
             * sql file
             */
            UserObject userObject = new UserObject("sqls");
            userObject.setParameter("path", "/");
            userObject.setParameter("showChildNodesMethod", "showFolderList");
            DatabaseTreeNode treeNode = new DatabaseTreeNode(userObject, SwingManager.getImageIcon("resource/folderopen.gif"), SwingManager.getImageIcon("resource/folder.gif"));
            this.rootNode.add(treeNode);
            SwingManager.expand(this.jTree, this.rootNode);
        }
        catch(Exception e) {
            logger.error(e.getMessage(), e);
            error(e);
        }
    }

    /**
     * @param node
     * @param methodName
     */
    void showChildNodes(DatabaseTreeNode node, String methodName) {
        try {
            Method method = this.getClass().getDeclaredMethod(methodName, new Class<?>[]{DatabaseTreeNode.class});
            method.invoke(this, new Object[]{node});
        }
        catch(Exception e) {
            logger.error(e.getMessage(), e);
            error(e);
        }
    }

    /**
     * @param node
     */
    void showTableList(DatabaseTreeNode node) {
        if(node.getChildCount() > 0) {
            return;
        }

        /**
         * 显示加载
         */
        String connectionName = ((UserObject)(node.getUserObject())).getString("name");
        node.setOpenIcon(SwingManager.getImageIcon("resource/loading.gif"));
        node.setCloseIcon(SwingManager.getImageIcon("resource/loading.gif"));
        this.jTree.updateUI();

        try {
            List<Table> list = TableUtil.getTableList(connectionName, false);
            node.removeAllChildren();

            if(list == null || list.isEmpty()) {
                logger.debug("no table !");
                node.setOpenIcon(SwingManager.getImageIcon("resource/dbopen.gif"));
                node.setCloseIcon(SwingManager.getImageIcon("resource/dbclose.gif"));
                this.jTree.updateUI();
                return;
            }

            logger.debug("tables.count: {}", list.size());
            Iterator<Table> iterator = list.iterator();
            ImageIcon tableIcon = SwingManager.getImageIcon("resource/table.gif");

            while(iterator.hasNext()) {
                Table table = iterator.next();
                UserObject userObject = new UserObject(table.getTableName(), "/webcat/table/edit");
                userObject.setParameter("name", connectionName);
                userObject.setParameter("tableName", table.getTableName());
                DatabaseTreeNode treeNode = new DatabaseTreeNode(userObject, tableIcon);
                treeNode.setAllowsChildren(true);
                node.add(treeNode);
            }

            node.setOpenIcon(SwingManager.getImageIcon("resource/dbopen.gif"));
            node.setCloseIcon(SwingManager.getImageIcon("resource/dbopen.gif"));
            this.jTree.updateUI();
            SwingManager.expand(this.jTree, node);
        }
        catch(Exception e) {
            logger.error(e.getMessage(), e);
            error(e);
        }
    }

    /**
     * @param node
     */
    void showFolderList(DatabaseTreeNode node) {
        if(node.getChildCount() > 0) {
            return;
        }

        /**
         * 显示加载
         */
        String path = ((UserObject)(node.getUserObject())).getString("path");
        node.setOpenIcon(SwingManager.getImageIcon("resource/loading.gif"));
        node.setCloseIcon(SwingManager.getImageIcon("resource/loading.gif"));
        this.jTree.updateUI();

        try {
            File work = new File("sqls");
            File file = Webcat.getFile(work, path);
            ImageIcon fileIcon = SwingManager.getImageIcon("resource/file.gif");
            ImageIcon folderIcon = SwingManager.getImageIcon("resource/folder.gif");
            ImageIcon folderOpenIcon = SwingManager.getImageIcon("resource/folderopen.gif");

            if(file != null) {
                File[] files = file.listFiles();
                int startIndex = work.getCanonicalPath().length();

                if(files != null && files.length > 0) {
                    for(File f : files) {
                        if(f.isDirectory()) {
                            UserObject userObject = new UserObject(f.getName());
                            userObject.setParameter("path", f.getAbsolutePath().substring(startIndex));
                            userObject.setParameter("showChildNodesMethod", "showFolderList");
                            DatabaseTreeNode treeNode = new DatabaseTreeNode(userObject, folderOpenIcon, folderIcon);
                            treeNode.setAllowsChildren(true);
                            node.add(treeNode);
                        }
                    }

                    for(File f : files) {
                        if(f.isFile()) {
                            UserObject userObject = new UserObject(f.getName(), "/webcat/sql/list");
                            userObject.setParameter("path", f.getAbsolutePath().substring(startIndex));
                            userObject.setParameter("showChildNodesMethod", "showTableListBySql");
                            DatabaseTreeNode treeNode = new DatabaseTreeNode(userObject, fileIcon);
                            treeNode.setAllowsChildren(true);
                            node.add(treeNode);
                        }
                    }
                }
            }
            node.setOpenIcon(folderOpenIcon);
            node.setCloseIcon(folderIcon);
            this.jTree.updateUI();
            SwingManager.expand(this.jTree, node);
        }
        catch(Exception e) {
            logger.error(e.getMessage(), e);
            error(e);
        }
    }

    /**
     * @param node
     */
    void showTableListBySql(DatabaseTreeNode node) {
        if(node.getChildCount() > 0) {
            return;
        }

        /**
         * 显示加载
         */
        String path = ((UserObject)(node.getUserObject())).getString("path");
        node.setOpenIcon(SwingManager.getImageIcon("resource/loading.gif"));
        node.setCloseIcon(SwingManager.getImageIcon("resource/loading.gif"));
        this.jTree.updateUI();

        try {
            List<Table> tableList = SqlFile.getTableList(path);

            if(tableList != null && tableList.size() > 0) {
                for(Table table : tableList) {
                    UserObject userObject = new UserObject(table.getTableName(), "/webcat/sql/edit");
                    userObject.setParameter("tableName", table.getTableName());
                    userObject.setParameter("path", path);
                    DatabaseTreeNode treeNode = new DatabaseTreeNode(userObject, SwingManager.getImageIcon("resource/table.gif"));
                    treeNode.setAllowsChildren(true);
                    node.add(treeNode);
                }
            }
            node.setOpenIcon(SwingManager.getImageIcon("resource/file.gif"));
            node.setCloseIcon(SwingManager.getImageIcon("resource/file.gif"));
            this.jTree.updateUI();
            SwingManager.expand(this.jTree, node);
        }
        catch(Exception e) {
            logger.error(e.getMessage(), e);
            error(e);
        }
    }

    /**
     * @param runnable
     */
    void loading(Runnable runnable) {
        logger.info("loading.thread: {}", Thread.currentThread().getName());

        if(this.loadingDialog == null) {
            this.loadingDialog = new LoadingDialog(this, "loading", true);
        }
        this.loadingDialog.open(runnable);
    }

    /**
     * @return LocalStorage
     */
    @Override
    public LocalStorage getLocalStorage() {
        return this.localStorage;
    }

    /**
     * @param localStorage
     */
    @Override
    public void save(LocalStorage localStorage) {
        localStorage.save(new File(LOCAL_STORAGE_FILE));
    }

    void loadTable() {
        File file = showOpenDialog((String)null);

        if(file != null) {
            try {
                logger.info("load table: {}", file.getAbsoluteFile());
                Table table = TableUtil.parse(file, "utf-8");

                if(table != null) {
                    Map<String, Object> params = new HashMap<String, Object>();
                    params.put("table", table);
                    this.dispatch("/webcat/table/edit", params);
                }
            }
            catch (Exception e) {
                logger.error(e.getMessage(), e);
            }
        }
    }

    /**
     * @param fileName
     * @return File
     */
    File showOpenDialog(String fileName) {
        LocalStorage localStorage = this.getLocalStorage();
        String dir = localStorage.getValue(Constant.KEY_CURRENT_DIRECTORY, ".");
        JFileChooser chooser = new JFileChooser();
        FileNameExtensionFilter filter = new FileNameExtensionFilter("XML & XMLS", "xml", "xmls");
        chooser.setCurrentDirectory(new File(dir));
        chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
        chooser.setFileFilter(filter);

        if(fileName != null) {
            chooser.setSelectedFile(new File(fileName));
        }

        int returnValue = chooser.showSaveDialog(this);
        localStorage.setValue(Constant.KEY_CURRENT_DIRECTORY, chooser.getCurrentDirectory().getAbsolutePath());

        if(returnValue == JFileChooser.APPROVE_OPTION) {
           return chooser.getSelectedFile();
        }
        return null;
    }

    /**
     * 
     */
    public static void setLookAndFeel() {
        String lookAndFeelClassName = "com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel";
        // lookAndFeelClassName = "javax.swing.plaf.metal.MetalLookAndFeel";
        // lookAndFeelClassName = "com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel";
        // lookAndFeelClassName = "com.sun.java.swing.plaf.motif.MotifLookAndFeel";
        lookAndFeelClassName = "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
        // lookAndFeelClassName = "com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel";

        try {
            javax.swing.UIManager.setLookAndFeel(lookAndFeelClassName);
        }
        catch(ClassNotFoundException e) {
            logger.warn(e.getMessage());
        }
        catch(InstantiationException e) {
            logger.warn(e.getMessage());
        }
        catch(IllegalAccessException e) {
            logger.warn(e.getMessage());
        }
        catch(UnsupportedLookAndFeelException e) {
            logger.warn(e.getMessage());
        }
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        MainFrame.setLookAndFeel();
        MainFrame frame = new MainFrame();
        frame.open();
    }
}
